feat(minipay): redirect to Account page and hide Governance tab until staked#480
feat(minipay): redirect to Account page and hide Governance tab until staked#480
Conversation
… staked MiniPay users now land on the Account page instead of the Staking page, and the Governance tab is hidden until they have staked (stCELO balance > 0). Both changes are gated behind the isMiniPay flag and don't affect the regular web app.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 Changed routes:
Commit c466ad9 (https://celo-mondo-r54i4life-c-labs.vercel.app). |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b7e0634dc9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (isMiniPay) { | ||
| router.replace('/account'); |
There was a problem hiding this comment.
Gate MiniPay home redirect on wallet availability
This redirect is unconditional for MiniPay, so it also runs when no wallet address is connected (or before wagmi finishes hydrating). In that state, /account immediately redirects back to / via usePageInvariant(!!address, '/') in src/app/account/page.tsx, creating a / ↔ /account navigation loop for MiniPay users and leaving no stable landing page. Redirecting only after account readiness (or when address is present) avoids that loop.
Useful? React with 👍 / 👎.
| const { address } = useAccount(); | ||
| const trackEvent = useTrackEvent(); | ||
| const isMiniPay = useIsMiniPay(); | ||
| const { stCELOBalances } = useStCELOBalance(address); |
There was a problem hiding this comment.
Avoid stCELO polling for non-MiniPay navigation
The new useStCELOBalance(address) call executes for every connected user, even outside MiniPay, because the hook is not gated and its internal queries are enabled by !!address with periodic refetching. Since hideInMiniPayUntilStaked is only checked later in the filters, regular web users now do recurring stCELO RPC reads (and can see related error toasts) despite this feature being MiniPay-only.
Useful? React with 👍 / 👎.
MiniPay auto-connects the wallet asynchronously, so the redirect to /account was hitting the usePageInvariant guard before the address was available, causing a 404/redirect loop. Skip the guard for MiniPay users since they will always auto-connect.
…ount Prevents the validators table from flashing briefly before the redirect to /account completes.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ea1f25361b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| <ul className="flex list-none items-center justify-center space-x-6 overflow-hidden"> | ||
| {LINKS(!!address) | ||
| .filter((l) => !(isMiniPay && l.hideInMiniPay)) | ||
| .filter((l) => !(isMiniPay && l.hideInMiniPayUntilStaked && !hasStaked)) |
There was a problem hiding this comment.
Gate MiniPay governance on CELO stake, not stCELO balance
The new MiniPay Governance filter depends on hasStaked, but hasStaked is derived only from useStCELOBalance; MiniPay users are forced into CELO mode (src/utils/useStakingMode.tsx:23) and stake through the CELO flow, so they can complete staking while stCELOBalances.total remains 0n. In that path, Governance stays hidden indefinitely instead of reappearing after the user has staked.
Useful? React with 👍 / 👎.
|
|
||
| const { groups, totalVotes } = useValidatorGroups(); | ||
|
|
||
| if (isMiniPay) return null; |
There was a problem hiding this comment.
Avoid running validator query before MiniPay early return
MiniPay now redirects away from / and returns null, but this happens only after useValidatorGroups() runs, so each MiniPay home visit still triggers the full validator-group fetch path and its error-toast side effects (useToastError in src/features/validators/useValidatorGroups.ts) for data that is never rendered. This adds avoidable RPC load and can show irrelevant errors during redirect.
Useful? React with 👍 / 👎.
Shows a CTA card with staking description and Stake button for MiniPay users who haven't staked yet. Uses the existing CtaCard pattern and opens the StakeStCELO transaction flow on click.
MiniPay users are forced into CELO mode and stake through the CELO flow, so stCELO balance stays 0. Switch to useLockedBalance (locked CELO in governance) for the Governance tab visibility check and the Account page staking CTA.
Extract StakingPage into a child component so that useValidatorGroups() is never called when isMiniPay is true. Avoids unnecessary RPC calls and error toasts during the redirect to /account.
Replace 2-column CtaCard grid with a single-column stacked layout to avoid empty space next to the text on mobile.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 496abbb163
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| onClick={() => | ||
| showTxModal(TransactionFlowType.StakeStCELO, { action: StakeActionType.Stake }) | ||
| } |
There was a problem hiding this comment.
Open CELO lock flow from the MiniPay stake CTA
The new StakeCeloCta button opens TransactionFlowType.StakeStCELO, but Governance visibility in MiniPay is gated by lockedBalance > 0n in src/components/nav/NavBar.tsx. In the MiniPay scenario this means a user with no locked CELO can follow this CTA, complete staking, and still never satisfy the nav gate (because stCELO deposit does not increase LockedGold), so the CTA fails to unlock the Governance access it promises.
Useful? React with 👍 / 👎.
When the lock form is shown as a prerequisite (e.g. user has no locked CELO and tries to stake), the modal header now correctly shows "Lock CELO" instead of "Stake CELO", and the onConfirmed callback is passed through so the success confirmation screen appears after the lock transaction.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 436424ea33
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| ) { | ||
| Component = <LockForm showTip={true} />; | ||
| header = 'Lock CELO'; | ||
| Component = <LockForm showTip={true} onConfirmed={onConfirmed} />; |
There was a problem hiding this comment.
Preserve original action after prerequisite lock completes
Passing onConfirmed into the prerequisite LockForm changes the flow for Stake, Delegate, Upvote, and Vote when the user has no locked CELO: after a successful lock, confirmationDetails is set and TransactionFlow switches to TransactionConfirmation (which closes/reloads) instead of returning to the originally requested form. This regresses the existing one-modal progression and forces users to restart the action (often losing context like proposal-specific voting intent).
Useful? React with 👍 / 👎.
| const { lockedBalance } = useLockedBalance(address); | ||
| const hasStaked = lockedBalance > 0n; |
There was a problem hiding this comment.
Gate locked-balance polling to MiniPay-only rendering
The navbar now calls useLockedBalance(address) unconditionally for every connected user, but hasStaked is only used for the MiniPay-specific governance filter. Because useLockedBalance enables periodic refetching (BALANCE_REFRESH_INTERVAL, 5s) and emits toast errors on failures, non-MiniPay users now incur continuous extra RPC reads and can see unrelated error toasts for a feature branch they never use.
Useful? React with 👍 / 👎.
Two changes: 1. TransactionFlow: check confirmationDetails before prerequisite checks. Previously the lockedBalance <= 0 check took priority, so after a successful prerequisite lock the LockForm re-rendered instead of showing the confirmation screen (until the 5s balance refetch caught up). 2. useLockedStatus: add refetchInterval (5s) matching useLockedBalance. Without this, the locked balance on the account page relied on a page reload to refresh — which may not clear React Query cache in MiniPay's WebView, leaving "Total locked" stuck at 0.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 63eaf3729d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const { lockedBalance } = useLockedBalance(address); | ||
| const hasStaked = lockedBalance > 0n; |
There was a problem hiding this comment.
Compute MiniPay staking gate from signing account
The MiniPay Governance gate is based on useLockedBalance(address), which checks only the connected wallet, but governance eligibility in this codebase is resolved through vote-signer indirection (useVoteSignerToAccount in src/features/governance/hooks/useVotingStatus.ts and src/features/transactions/TransactionFlow.tsx). If a MiniPay wallet is a vote signer for another staked account, address can have 0n locked balance while the signing account still has voting power, so this nav filter hides Governance for a user who can otherwise participate.
Useful? React with 👍 / 👎.
- ?minipay or ?minipay=true forces MiniPay UI in a normal browser - ?address=0x... views any account read-only (hides write actions) - Both can be combined: ?address=0x...&minipay
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 920befe601
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| {!isReadOnly && !isVoteSigner && ( | ||
| <LockButtons className="flex justify-between md:hidden" mode={mode} /> | ||
| )} |
There was a problem hiding this comment.
Disable write actions when account is marked read-only
In read-only mode (address query param present), this change hides only the lock buttons but still renders the transactional tables below. Those tables expose actions like stake/unstake/activate via useTransactionModal (see ActiveStakesTable), and TransactionFlow executes against the connected wallet from useAccount(), not the overridden address being viewed. That creates a misleading state where users can initiate wallet transactions while viewing another account’s data.
Useful? React with 👍 / 👎.
| const [address] = useState(() => { | ||
| if (typeof window === 'undefined') return undefined; | ||
| const param = new URLSearchParams(window.location.search).get('address'); | ||
| if (param && isAddress(param)) return param as Address; |
There was a problem hiding this comment.
Re-read address query param on navigation updates
useAddressParam snapshots window.location.search once in useState and never updates it, so client-side transitions between different /account?address=... URLs will keep showing the first address until a full reload. This can leave the account page showing stale balances/labels after in-app navigation or browser history changes.
Useful? React with 👍 / 👎.
MiniPay's provider intercepts eth_sendTransaction to add feeCurrency for gas abstraction (CIP-64). This reconstruction appears to drop the value field, causing payable calls like lock() to send 0 CELO. By setting feeCurrency explicitly before the tx reaches the provider, MiniPay may preserve the original transaction fields including value.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3ee8a1309a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| useEffect(() => { | ||
| if (isMiniPay) { | ||
| router.replace('/account'); |
There was a problem hiding this comment.
Preserve minipay override when redirecting from home
The home redirect drops the current query string, so a session opened at /?minipay is immediately sent to /account without minipay, and useIsMiniPay() on the destination page falls back to window.ethereum?.isMiniPay. In a normal browser this disables the override after one navigation (and can bounce users back to / when no wallet is connected), which breaks the new query-param MiniPay emulation flow.
Useful? React with 👍 / 👎.
| const [isMiniPay] = useState(() => { | ||
| if (typeof window === 'undefined') return false; | ||
| const params = new URLSearchParams(window.location.search); | ||
| if (params.has('minipay')) return params.get('minipay') !== 'false'; |
There was a problem hiding this comment.
Re-read MiniPay override when the URL query changes
This hook snapshots window.location.search once in component state and never updates it, so client-side transitions (or back/forward) between URLs that differ in ?minipay keep using the stale initial value. As a result, MiniPay-gated behavior (redirects, nav filtering, fee-currency logic, mode forcing) can remain incorrect after navigation.
Useful? React with 👍 / 👎.
Setting feeCurrency explicitly did not prevent MiniPay from dropping the value field. This is a MiniPay provider bug with payable function calls.
Adds feeCurrency to writeContract for MiniPay with isMiniPay in the useCallback deps array and a debug log to confirm value and isMiniPay state at tx submission time.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b100d05010
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| window.alert( | ||
| `isMiniPay=${isMiniPay} value=${args.value} feeCurrency=${(txArgs as any).feeCurrency}`, | ||
| ); |
There was a problem hiding this comment.
Remove debug alert from transaction send path
The newly added window.alert(...) runs for every non-WalletConnect transaction submission, including regular web users when isMiniPay is false. This inserts a blocking browser modal into the core write flow, forces an extra user interaction before each transaction, and can break automated or embedded wallet flows that expect uninterrupted submission. This should not ship in production transaction code.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c466ad9ed5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| {isReadOnly ? ( | ||
| <div className="align-right flex flex-col items-end"> |
There was a problem hiding this comment.
Keep vote-signer banner when rendering read-only account
This new isReadOnly branch masks the existing vote-signer UI path, so /?address=<vote-signer> now shows “Viewing account ” even though most balances and tables are still derived from signingFor (via useBalance(signingFor), useLockedStatus(signingFor), etc.). In that scenario the page labels one account while rendering another account’s staking/governance data, which is misleading for shared read-only links. Preserve the vote-signer context (or align data sourcing with the displayed address) in read-only mode.
Useful? React with 👍 / 👎.


Summary
router.replace)isMiniPay— no impact on the regular web appChanges
src/app/page.tsx: AddeduseEffectredirect to/accountfor MiniPay userssrc/components/nav/NavBar.tsx: AddedhideInMiniPayUntilStakedflag on Governance link, checked againstuseStCELOBalancein both desktop and mobile navTest plan